#ifndef COMMON_H
#define COMMON_H



namespace RAYTRACER
{
const double PIOVER180 = 0.017453292519943295769236907684886;

class _point3 {
public:
	_point3 () : x(0.0f), y (0.0f), z(0.0f) {}
	_point3 (float _x, float _y, float _z): x(_x), y(_y), z(_z) {}
	_point3 (const _point3 & p) : x(p.x), y(p.y), z(p.z) {} 
	float x, y, z;
};

class _vector3 {
public:
	float x, y, z;
        _vector3 () : x(0.0f), y (0.0f), z(0.0f) {}
        _vector3 (float _x, float _y, float _z): x(_x), y(_y), z(_z) {}
        _vector3 (const _vector3 & p) : x(p.x), y(p.y), z(p.z) {}

    _vector3& operator += (const _vector3 &v2)
	{
	    this->x += v2.x;
        this->y += v2.y;
        this->z += v2.z;
	    return *this;
    }
	float length()
	{
		return sqrt(x*x + y *y + z *z);
	}
	_vector3  normal ()
	{
		float len = this->length();
		return _vector3 (x / len, y / len, z / len);
	}
};

inline _point3 operator + (const _point3&p, const _vector3 &v)
{
	_point3 p2 = _point3(p.x + v.x, p.y + v.y, p.z + v.z );
	return p2;
}

inline _point3 operator - (const _point3&p, const _vector3 &v)
{
	_point3 p2 = _point3(p.x - v.x, p.y - v.y, p.z - v.z );
	return p2;
}

inline _vector3 operator + (const _vector3&v1, const _vector3 &v2)
{
	_vector3 v = _vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z );
	return v;
}

inline _vector3 operator - (const _point3 & p1, const _point3 & p2)
{
	_vector3 v = _vector3(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z );
	return v;
}

inline _vector3 operator - (const _vector3 & v1, const _vector3 & v2){
	_vector3 v = _vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z );
	return v;
}

inline _vector3 operator * (float c, const _vector3 &v)
{
	_vector3 v2 = _vector3(v.x *c, v.y * c, v.z * c );
	return v2;
}

inline _vector3 operator * (const _vector3 &v, float c)
{
	return (c * v) ;
}

inline float operator * (const _vector3 & lhs, const _vector3 & rhs ) 
{
	return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
}

inline _vector3 operator ^ (const _vector3 & lhs, const _vector3 & rhs) 
{
	return _vector3 (lhs.y * rhs.z - lhs.z * rhs.y, 
			(lhs.z * rhs.x - lhs.x * rhs.z),
			lhs.x * rhs.y - lhs.y * rhs.x );
}

enum OFFSET 
{
    OFFSET_RED = 0,
    OFFSET_GREEN = 1,
    OFFSET_BLUE = 2,
    OFFSET_ALPHA  = 3
};
class _color 
{
public:
	_color (const float r, const float g, const float  b ):
		red (r), green (g), blue(b) {}
	_color (const _color & c) : red (c.red), green (c.green), blue(c.blue) {}
	_color () : red (0.0f), green (0.0f), blue (0.0f){}

    float red, green, blue;

    inline _color & operator += (const _color & c ) {
	    this->red +=  c.red;
        this->green += c.green;
        this->blue += c.blue;
	    return *this;
    }

    inline float & getChannel(OFFSET offset )
    {
        return reinterpret_cast<float*>(this)[offset];
    }

    inline float getChannel(OFFSET offset ) const
    {
        return reinterpret_cast<const float*>(this)[offset];
    }
	inline const short getShortChannel (OFFSET offset) const
	{
		return gammaCorrection(reinterpret_cast<const float*>(this)[offset]);
	}
	inline void getShort (short & r, short & g, short &b) const
	{
		r = gammaCorrection(red) ; 
		g = gammaCorrection(green) ;
		b = gammaCorrection(blue) ;
	}
private:
	inline short gammaCorrection (float c) const 
	{

		return (c <= 0.0031308f ? (12.92f * c) : (1.055f * powf(c, 0.4166667f) - 0.055f));
	}
};

inline _color operator * (const _color & lhs, const _color & rhs ) 
{
	return _color (lhs.red * rhs.red, lhs.green * rhs.green, lhs.blue * rhs.blue);
}

inline _color operator + (const _color&c1, const _color &c2 ) 
{
	return _color (c1.red + c2.red, c1.green + c2.green, c1.blue + c2.blue);
}

inline _color operator * (float coef, const _color &c ) 
{
	return _color (c.red * coef, c.green * coef, c.blue * coef);
}
inline _color operator * (const _color &c, float coef) 
{
	return (coef * c);
}

typedef _color Color ;
typedef _point3 Point3 ;
typedef _vector3 Vector3 ; 

}


#endif // COMMON_H
